﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.IO;

namespace Business
{
    public class UserManagement
    {
        FosIntelEntities _en = new FosIntelEntities();
        public bool Authenticate(string email, string password)
        {

            fos_User user = (from a in _en.fos_User
                             where a.Email == email &&
                             a.Password == password
                             && a.IsDeleted == 0 && a.isActive == true
                             select a).FirstOrDefault();
            if (user != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public User GetUser(string email)
        {
            fos_User user = (from a in _en.fos_User
                             where a.Email == email
                             select a).FirstOrDefault();

            User userobj = new User();
            userobj.id = user.Id;
            userobj.email = user.Email;
            userobj.userRoles = user.fos_UserLinkRole.Where(a => a.IsDeleted != 1).ToList();

            return userobj;

        }

        public fos_User GetUser(long userId)
        {
            fos_User user = (from a in _en.fos_User
                             where a.Id == userId
                             select a).FirstOrDefault();
            return user;

        }

        public void SaveUser(fos_User userobj, string retypePassword, bool activateInstantly)
        {
            if (string.IsNullOrEmpty(userobj.Name) || string.IsNullOrEmpty(userobj.Phone) || string.IsNullOrEmpty(userobj.WWID) || string.IsNullOrEmpty(userobj.Email)) throw new Exception("Fields cannot be empty!");
            if (userobj.Password != retypePassword) throw new Exception("The password and its confirm are not the same");
            if (!Common.IsEmail(userobj.Email)) throw new Exception("Invalid Email Address!");
            
            userobj.LastModifiedDate = DateTime.Now;
            
            fos_User user = (from a in _en.fos_User
                             where a.Email == userobj.Email 
                             select a).FirstOrDefault();
            
            if (user != null && user.IsDeleted != 1)
                throw new Exception("Email address is already a registered user!");

            if (user != null && user.IsDeleted == 1) // this user is being deleted before. update back
            {
                userobj.LastModifiedDate = DateTime.Now;
                userobj.Id = user.Id;
                _en.Entry(user).CurrentValues.SetValues(userobj);
                _en.SaveChanges();
                return;
            }

            // New User
            if (!activateInstantly) userobj.isActive = false;
            else userobj.isActive = true;

            userobj.CreatedBy = "User Management";
            userobj.CreatedDate = DateTime.Now;
            
            _en.fos_User.Add(userobj);
            _en.SaveChanges();

        }

        public void UpdateUser(fos_User userobj, string siteInfo, string roleInfo, string printerInfo)
        {
            var original = _en.fos_User.Find(userobj.Id);

            if (original != null)
            {
                _en.Entry(original).CurrentValues.SetValues(userobj);
                _en.SaveChanges();

                if (siteInfo != "")
                {
                    // associate site to the original user

                    AssociateSite(original, siteInfo);
                    AssociateCatererSite(original, siteInfo);
                }
                if (roleInfo != "")
                {
                    // associate role to the original user
                    AssociateRole(original, roleInfo);
                }
                if (printerInfo != "")
                {
                    // associate role to the original user
                    AssociatePrinter(original, printerInfo);
                }
            }
        }

        public void DeleteUser(string id)
        {
            long idint = Convert.ToInt64(id);
            fos_User user = (from a in _en.fos_User
                             where a.Id == idint
                             select a).FirstOrDefault();
            user.isActive = false;
            user.IsDeleted = 1;
            _en.SaveChanges();
        }

        //Id, Phone, Email, LastModifiedDate, lastModifiedBy, roleid, siteid, siteInfo
        public void UpdateUserProperty(string id, string phone, string email, string lastModifiedDate, string lastModifiedBy, string roleid, string siteid, string printerid)
        {
            try
            {
                fos_User user = (from a in _en.fos_User
                                 where a.Email == email
                                 select a).FirstOrDefault();
                if (user != null)
                {
                    if (phone.Trim() != "") user.Phone = phone.Trim();
                    //if (email.Trim() != "") 
                    user.LastModifiedDate = DateTime.Now;
                    //user.LastModifiedBy = lastModifiedBy
                    UpdateUser(user, siteid, roleid, printerid);

                }
            }
            catch (Exception e)
            {
                if (e.Message == "User already associated to the site!")
                {
                    // it's okay.
                }
                else
                {
                    throw new Exception("Fail to update user property!");
                }
            }
        }

        public void SendActivationLink(fos_User user)
        {

            string to = user.Email;
            string subject = "Food Ordering System Notification: Congratulation! Your Registration has been approved.";
            //string webLink = Common.GetFullUrl("~/Activation.aspx?") + Utility.Encryption.EncryptQueryString("mail") + "=" + Utility.Encryption.EncryptQueryString("abcd1234", to);
            string securitystr = Common.EncryptQueryString(user.Email);
            string webLink = Common.GetFullUrl("~/Activation.aspx?") + "email=" + Common.EncryptQueryString(user.Email);
            string checksecurity = Common.DecryptQueryString(securitystr);

            StringBuilder bodyAdmin = new StringBuilder();
            bodyAdmin.Append("<html><body>");
            bodyAdmin.AppendFormat("Dear {0},<br /><br />", user.Name);
            bodyAdmin.AppendFormat("Your account is approved. Please activate through the following link. {0} <br />", webLink);

            //bodyAdmin.AppendFormat("<br />Decrypted email = {0}. <br />", checksecurity);

            bodyAdmin.Append("You  may now access to the Portal. Thank you.<br /><br />Best Regards,<br />FOS");
            bodyAdmin.Append("</body></html>");
            Common.SendMail(subject, to, bodyAdmin.ToString());

        }

        public void SendNewPassword(fos_User user, string newPassword)
        {

            string to = user.Email;
            string subject = "Food Ordering System Notification: Congratulation! Your password has been reset.";

            string webLink = Common.GetFullUrl("~/Default.aspx");
            StringBuilder bodyAdmin = new StringBuilder();
            bodyAdmin.Append("<html><body>");
            bodyAdmin.AppendFormat("Dear {0},<br /><br />", user.Name);

            bodyAdmin.AppendFormat("Your password has been reset and send to {0}. <br />", user.Email);
            bodyAdmin.AppendFormat("Your new is {0}. <br />", newPassword);
            bodyAdmin.AppendFormat("Please login through the following link. {0} <br />", webLink);

            bodyAdmin.Append("You  may now access to the Portal. Thank you.<br /><br />Best Regards,<br />FOS");
            bodyAdmin.Append("</body></html>");
            Common.SendMail(subject, to, bodyAdmin.ToString());

        }

        public void ChangePassword(long userId, string oldPassword, string newPassword, string retypePassword)
        {
            fos_User user = (from a in _en.fos_User
                             where a.Id == userId
                             select a).FirstOrDefault();
            if (string.IsNullOrEmpty(oldPassword) || string.IsNullOrEmpty(newPassword) || string.IsNullOrEmpty(retypePassword)) throw new Exception("Fields cannot be empty!");
            if (Security.EncodePassword(oldPassword) != user.Password) throw new Exception("Your existing password is different!");
            if (newPassword != retypePassword) throw new Exception("The password and its confirm are not the same");


            user.Password = Security.EncodePassword(newPassword);   //32 hexadecimal
            _en.SaveChanges();

        }

        public void ForgetPassword(string loginEmail)
        {
            if (string.IsNullOrEmpty(loginEmail)) throw new Exception("Fields cannot be empty!");

            fos_User user = (from a in _en.fos_User
                             where a.Email == loginEmail
                             select a).FirstOrDefault();

            if (user == null) throw new Exception("Your email account does not exist. Please register again.");
            if (user.IsDeleted == 1) throw new Exception("Your email account has been deleted previously. Please register again.");

            string rStr = Path.GetRandomFileName();
            rStr = rStr.Replace(".", ""); // For Removing the .
            rStr.Replace("-", "");
            rStr = rStr.Substring(0, 6);

            user.Password = Security.EncodePassword(rStr);
            _en.SaveChanges();

            SendNewPassword(user, rStr);
        }

        public void ActivateAccount(string email)
        {
            fos_User user = (from a in _en.fos_User
                             where a.Email == email
                             select a).FirstOrDefault();
            user.isActive = true ;
            _en.SaveChanges();
        }

        public void AssociateRole(fos_User userobj, string roleid)
        {
            // check if the association exist before.
            if (string.IsNullOrEmpty(roleid)) throw new Exception("Role selection cannot be empty!");

            fos_User user = (from a in _en.fos_User
                             where a.Email == userobj.Email
                             select a).FirstOrDefault();
            if (user == null)
                throw new Exception("Email address is not yet a registered user!");

            long roleidint = Convert.ToInt64(roleid);

            fos_UserLinkRole userrole = (from a in _en.fos_UserLinkRole
                                         where a.UserId == userobj.Id && a.IsDeleted != 1
                                         select a).FirstOrDefault();


            if (userrole != null)
            {
                if (userrole.RoleId == Convert.ToInt32(roleidint)) return; //throw new Exception("User already associated to the site!");
                else
                {
                    // delete old association
                    userrole.IsDeleted = 1;
                    _en.SaveChanges();
                }
            }

            // Create new association
            userrole = new fos_UserLinkRole();
            userrole.IsDeleted = 0;
            userrole.CreatedBy = "User Management";
            userrole.CreatedDate = DateTime.Now;
            userrole.LastModifiedDate = DateTime.Now;
            userrole.RoleId = roleidint;
            userrole.UserId = userobj.Id;
            _en.fos_UserLinkRole.Add(userrole);
            _en.SaveChanges();

        }


        public void AssociateRoleUserList(fos_User userobj, string roleid,string email)
        {
            // check if the association exist before.
            if (string.IsNullOrEmpty(roleid)) throw new Exception("Role selection cannot be empty!");

            fos_User user = (from a in _en.fos_User
                             where a.Email == userobj.Email
                             select a).FirstOrDefault();
            if (user == null)
                throw new Exception("Email address is not yet a registered user!");

            long roleidint = Convert.ToInt64(roleid);

            // Getting all user role, reuse isDeleted row if needed
            List<fos_UserLinkRole> userroles = (from a in _en.fos_UserLinkRole
                                         where a.UserId == userobj.Id 
                                         select a).ToList<fos_UserLinkRole>();
            // check is the role already associated
             fos_UserLinkRole  checkRoleExist =  (from b in userroles where b.IsDeleted == 0 && b.RoleId==roleidint select b).FirstOrDefault();
             if (checkRoleExist != null)
                 throw new Exception("User already associated with the role!");
             else
             {
                 // if it is deleted before, updated isdeleted to 0
                 fos_UserLinkRole RoleDeleted = (from b in userroles where b.RoleId == roleidint select b).FirstOrDefault();
                 if (RoleDeleted != null)
                 {
                     RoleDeleted.IsDeleted = 0;
                     RoleDeleted.LastModifiedDate = DateTime.Now;
                     RoleDeleted.LastModifiedBy = email;
                     _en.SaveChanges();

                 }
                 else
                 {
                     // Create new association
                     fos_UserLinkRole userrole = new fos_UserLinkRole();
                     userrole.IsDeleted = 0;
                     userrole.CreatedBy = email;
                     userrole.CreatedDate = DateTime.Now;
                     userrole.LastModifiedDate = DateTime.Now;
                     userrole.LastModifiedBy = email;
                     userrole.RoleId = roleidint;
                     userrole.UserId = userobj.Id;
                     _en.fos_UserLinkRole.Add(userrole);
                     _en.SaveChanges();

                 }

             }
        }


        public void AssociateSite(fos_User userobj, string siteid)
        {
            // check if the association exist before.
            if (string.IsNullOrEmpty(siteid)) throw new Exception("Site selection cannot be empty!");

            fos_User user = (from a in _en.fos_User
                             where a.Email == userobj.Email
                             select a).FirstOrDefault();
            if (user == null)
                throw new Exception("Email address is not yet a registered user!");

            long siteidint = Convert.ToInt64(siteid);

            fos_UserLinkSite usersite = (from a in _en.fos_UserLinkSite
                                         where a.UserId == userobj.Id && a.IsDeleted != 1
                                         select a).FirstOrDefault();

            if (usersite != null)
            {
                if (usersite.SiteId == Convert.ToInt32(siteid)) return; //throw new Exception("User already associated to the site!");
                else
                {
                    // delete old association
                    usersite.IsDeleted = 1;
                    usersite.LastModifiedDate = DateTime.Now;
                    usersite.LastModifiedBy = "System Management";
                    _en.SaveChanges();
                }
            }

            // Create new association
            usersite = new fos_UserLinkSite();
            usersite.IsDeleted = 0;
            usersite.CreatedBy = "User Management";
            usersite.CreatedDate = DateTime.Now;
            usersite.LastModifiedDate = DateTime.Now;
            usersite.SiteId = siteidint;
            usersite.UserId = userobj.Id;
            _en.fos_UserLinkSite.Add(usersite);
            _en.SaveChanges();

        }

        public void AssociatePrinter(fos_User userobj, string printerid)
        {
            // check if the association exist before.
            if (string.IsNullOrEmpty(printerid)) throw new Exception("Printer selection cannot be empty!");

            fos_User user = (from a in _en.fos_User
                             where a.Email == userobj.Email
                             select a).FirstOrDefault();
            if (user == null)
                throw new Exception("Email address is not yet a registered user!");

            long printeridint = Convert.ToInt64(printerid);

            fos_SiteLinkPrinter userprinter = (from a in _en.fos_SiteLinkPrinter
                                               where a.UserId == userobj.Id && a.IsDeleted != 1
                                               select a).FirstOrDefault();

            if (userprinter != null)
            {
                if (userprinter.PrinterId == Convert.ToInt32(printerid)) return; //throw new Exception("User already associated to the site!");
                else
                {
                    // delete old association
                    userprinter.IsDeleted = 1;
                    userprinter.LastModifiedDate = DateTime.Now;
                    userprinter.LastModifiedBy = "User Management";
                    _en.SaveChanges();
                }
            }

            // Create new association
            userprinter = new fos_SiteLinkPrinter();
            userprinter.IsDeleted = 0;
            userprinter.CreatedBy = "User Management";
            userprinter.CreatedDate = DateTime.Now;
            userprinter.LastModifiedDate = DateTime.Now;
            userprinter.PrinterId = printeridint;
            userprinter.UserId = userobj.Id;
            _en.fos_SiteLinkPrinter.Add(userprinter);
            _en.SaveChanges();

        }

        public void AssociateCatererSite(fos_User userobj, string siteid)
        {
            // check if the association exist before.
            if (string.IsNullOrEmpty(siteid)) throw new Exception("Site selection cannot be empty!");

            fos_User user = (from a in _en.fos_User
                             where a.Email == userobj.Email
                             select a).FirstOrDefault();
            if (user == null)
                throw new Exception("Email address is not yet a registered user!");

            long siteidint = Convert.ToInt64(siteid);

            fos_SiteLinkCaterer usersite = (from a in _en.fos_SiteLinkCaterer
                                            where a.UserId == userobj.Id && a.IsDeleted != 1
                                            select a).FirstOrDefault();

            if (usersite != null)
            {
                if (usersite.SiteId == Convert.ToInt32(siteid)) return; //throw new Exception("User already associated to the site!");
                else
                {
                    // delete old association
                    usersite.IsDeleted = 1;
                    usersite.LastModifiedDate = DateTime.Now;
                    usersite.LastModifiedBy = "System Management";
                    _en.SaveChanges();
                }
            }

            // Create new association
            usersite = new fos_SiteLinkCaterer();
            usersite.IsDeleted = 0;
            usersite.CreatedBy = "User Management";
            usersite.CreatedDate = DateTime.Now;
            usersite.LastModifiedDate = DateTime.Now;
            usersite.SiteId = siteidint;
            usersite.UserId = userobj.Id;
            _en.fos_SiteLinkCaterer.Add(usersite);
            _en.SaveChanges();

        }
        public List<fos_User> GetUsersByRole(Int32 roleid)
        {
            List<fos_User> users = _en.fos_UserLinkRole.Where(r => r.RoleId == roleid && r.IsDeleted != 1)
                .Select(p => p.fos_User).Where(p => p.IsDeleted != 1).ToList();
            // Need to filter the fos_UserLinkSite where isDeleted !=  1

            List<fos_User> retusers = new List<fos_User>();

            foreach (fos_User user in users)
            {
                fos_UserLinkSite userlinksite = user.fos_UserLinkSite.Where(r => r.IsDeleted != 1).FirstOrDefault();
                if (userlinksite != null) retusers.Add(user);
            }

            return retusers;
        }

        public List<fos_User> GetAllUsers()
        {
            List<fos_User> users = (from a in _en.fos_User 
                                    select a).ToList<fos_User>();

            return users;

        }

        public void DeleteUserRole(long userlinkRoleId,string email)
        {
            fos_UserLinkRole userrole =  (from a in _en.fos_UserLinkRole
                                            where a.Id ==userlinkRoleId  select a).FirstOrDefault();
            userrole.IsDeleted = 1;
            userrole.LastModifiedDate = DateTime.Now;
            userrole.LastModifiedBy = email;
            _en.SaveChanges();
        }
    }



    public class User
    {
        public long id { get; set; }
        public string email { get; set; }

        public List<fos_UserLinkRole> userRoles { get; set; }
    }
}
